package main

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"gitee.com/czy233/go-ceph/rados"
)

var (
	caCert0 = "./gen_crypto/crypto-config/peerOrganizations/org1.demo.com/peers/peer0.org1.demo.com/tls/ca.crt"
	caCert1 = "./gen_crypto/crypto-config/peerOrganizations/org2.demo.com/peers/peer0.org2.demo.com/tls/ca.crt" // client's ca
	caCert2 = "./gen_crypto/crypto-config/peerOrganizations/org3.demo.com/peers/peer0.org3.demo.com/tls/ca.crt"
	caCert3 = "./gen_crypto/crypto-config/peerOrganizations/org4.demo.com/peers/peer0.org4.demo.com/tls/ca.crt"

	serverCert0 = "./gen_crypto/crypto-config/peerOrganizations/org1.demo.com/peers/peer0.org1.demo.com/tls/server.crt" // server's cert
	serverKey0  = "./gen_crypto/crypto-config/peerOrganizations/org1.demo.com/peers/peer0.org1.demo.com/tls/server.key" // server's private key
	serverCert1 = "./gen_crypto/crypto-config/peerOrganizations/org2.demo.com/peers/peer0.org2.demo.com/tls/server.crt" // server's cert
	serverKey1  = "./gen_crypto/crypto-config/peerOrganizations/org2.demo.com/peers/peer0.org2.demo.com/tls/server.key" // server's private key
	serverCert2 = "./gen_crypto/crypto-config/peerOrganizations/org3.demo.com/peers/peer0.org3.demo.com/tls/server.crt" // server's cert
	serverKey2  = "./gen_crypto/crypto-config/peerOrganizations/org3.demo.com/peers/peer0.org3.demo.com/tls/server.key" // server's private key
	serverCert3 = "./gen_crypto/crypto-config/peerOrganizations/org4.demo.com/peers/peer0.org4.demo.com/tls/server.crt" // server's cert
	serverKey3  = "./gen_crypto/crypto-config/peerOrganizations/org4.demo.com/peers/peer0.org4.demo.com/tls/server.key" // server's private key
)

type Server struct {
	ioctx  *rados.IOContext
	conn   *rados.Conn
	time   int
	From   int
	repair chan Repair
}

type Repair struct {
	obj    string
	offset int64
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	oid := r.FormValue("oid")
	data := make([]byte, 4096*1024)
	dlen, err := s.ioctx.Read(oid, data, 0)
	if err != nil {
		log.Println("cluster", Cluster, ":", "错误 响应恢复:读取", oid, err)
		return
	}
	if dlen != 4096*1024 {
		log.Println("cluster", Cluster, ":", "错误 数据长度不足 响应恢复:读取 ", oid, err)
		return
	}
	send_len, _ := w.Write(data)
	log.Println("cluster", Cluster, ":", "响应恢复:", oid, "sendlength: ", send_len)

}

func tls_server(cluster int) {
	conn, err := rados.NewConn()
	if err != nil {
		log.Println("cluster", Cluster, ":", "error when invoke a new connection:", err)
		return
	}
	defer conn.Shutdown()

	err = conn.ReadConfigFile("/etc/ceph/ceph.conf")
	if err != nil {
		log.Println("cluster", Cluster, ":", "error when read default config file:", err)
		return
	}

	err = conn.Connect()
	if err != nil {
		log.Println("cluster", Cluster, ":", "error when connect:", err)
		return
	}

	log.Println("cluster", Cluster, ":", "connect ceph cluster ok!")

	ioctx, err := conn.OpenIOContext("testbench")
	if err != nil {
		log.Println("cluster", Cluster, ":", "error when open IO context:", err)
		return
	}

	caCert := ClustercaCert(cluster)
	pool := x509.NewCertPool()
	addTrust(pool, caCert)

	s := Server{ioctx: ioctx, conn: conn, From: cluster}

	server := &http.Server{
		Addr:    ":1000" + strconv.Itoa(cluster),
		Handler: &s,
		TLSConfig: &tls.Config{
			ClientCAs:  pool,
			ClientAuth: tls.RequireAndVerifyClientCert,
		},
	}

	serverCert, serverKey := ClusterServer()

	err = server.ListenAndServeTLS(serverCert, serverKey) //添加服务端证书和密钥
	if err != nil {
		log.Println("cluster", Cluster, ":", "ListenAndServeTLS err:", err)
	}

	fmt.Println(pool.Subjects())
}

func ClusterServer() (certFile string, keyFile string) {
	switch Cluster {
	case 0:
		certFile = serverCert0
		keyFile = serverKey0
	case 1:
		certFile = serverCert1
		keyFile = serverKey1
	case 2:
		certFile = serverCert2
		keyFile = serverKey2
	case 3:
		certFile = serverCert3
		keyFile = serverKey3
	}
	return certFile, keyFile

}

func ClustercaCert(cluster int) (certFile string) {
	switch cluster {
	case 0:
		certFile = caCert0
	case 1:
		certFile = caCert1
	case 2:
		certFile = caCert2
	case 3:
		certFile = caCert3
	}
	return certFile
}
